// Copyright (c) 2022 Presto Labs Pte. Ltd.
// Author: qiang

#include "coin2/exchange/bitget_futures/api_order/native_rest_async_asio_subscriber.h"

#include <cstdlib>
#include <iostream>
#include <sstream>
#include <string>
#include <thread>

#include "coin2/base/log.h"

namespace coin2::exchange::bitget_futures::api_order {
using RestParams = coin2::exchange::order::BitgetFuturesRestParams;

void BitgetFuturesRestAsyncAsioSubscriber::QueryPosition(const std::string& product_type) {
  RestParams params;
  params.set_product_type(product_type);
  auto http_context = rest_client()->QueryAccountPosition(params);
  if (!http_context) return;
  http_context->handler =
      std::bind(&BitgetFuturesRestAsyncAsioSubscriber::HandleQuery, this, std::placeholders::_1);
  http_driver_->PostAsyncContext(http_context);
}

void BitgetFuturesRestAsyncAsioSubscriber::QueryOpenOrders(const std::string& product_type) {
  RestParams params;
  params.set_product_type(product_type);
  auto http_context = rest_client()->QueryOpenOrders(params);
  if (!http_context) return;
  http_context->handler =
      std::bind(&BitgetFuturesRestAsyncAsioSubscriber::HandleQuery, this, std::placeholders::_1);
  http_driver_->PostAsyncContext(http_context);
}

void BitgetFuturesRestAsyncAsioSubscriber::QueryBalance(const std::string& product_type) {
  RestParams params;
  params.set_product_type(product_type);
  auto http_context = rest_client()->QueryBalance(params);
  if (!http_context) return;
  http_context->handler =
      std::bind(&BitgetFuturesRestAsyncAsioSubscriber::HandleQuery, this, std::placeholders::_1);
  http_driver_->PostAsyncContext(http_context);
}

void BitgetFuturesRestAsyncAsioSubscriber::QueryAllOrders(const std::string& product_type) {
  RestParams params;
  params.set_product_type(product_type);
  auto current_time = GetCurrentTimestampMs();
  params.set_start_time(std::to_string(current_time - 1 * 60 * 1000));
  params.set_end_time(std::to_string(current_time));
  auto http_context = rest_client()->QueryAllOrders(params);
  if (!http_context) return;
  http_context->handler =
      std::bind(&BitgetFuturesRestAsyncAsioSubscriber::HandleQuery, this, std::placeholders::_1);
  http_driver_->PostAsyncContext(http_context);
}

std::set<std::string> BitgetFuturesRestAsyncAsioSubscriber::GetProductTypeList() {
  const auto symbol_list = native_symbols();
  if (!symbol_list.size()) {
    return {};
  }

  std::set<std::string> product_type_set;
  for (const std::string& native_symbol : symbol_list) {
    std::string type_str = Split(native_symbol, "_")[1];
    product_type_set.emplace(type_str);
  }

  return product_type_set;
}

void BitgetFuturesRestAsyncAsioSubscriber::QueryFillOrders(const std::string& product_type) {
  RestParams params;
  params.set_product_type(product_type);
  auto current_time = GetCurrentTimestampMs();
  params.set_start_time(std::to_string(current_time - 1 * 60 * 1000));
  params.set_end_time(std::to_string(current_time));
  auto http_context = rest_client()->QueryFills(params);
  if (!http_context) return;
  http_context->handler =
      std::bind(&BitgetFuturesRestAsyncAsioSubscriber::HandleQuery, this, std::placeholders::_1);
  http_driver_->PostAsyncContext(http_context);
}

void BitgetFuturesRestAsyncAsioSubscriber::SubscribeAsync() {
  LOG(INFO) << "Bitget Futures rest subscriber config: " << config_.DebugString();

  auto product_type_set = GetProductTypeList();

  AddPeriodicTask(
      std::bind(&BitgetFuturesRestAsyncAsioSubscriber::QueryBalance, this, std::placeholders::_1),
      config_.query_account_balance_period_sec(),
      "query_balance",
      product_type_set);

  AddPeriodicTask(
      std::bind(&BitgetFuturesRestAsyncAsioSubscriber::QueryPosition, this, std::placeholders::_1),
      config_.query_account_position_period_sec(),
      "query_position",
      product_type_set);

  AddPeriodicTask(
      std::bind(
          &BitgetFuturesRestAsyncAsioSubscriber::QueryOpenOrders,
          this,
          std::placeholders::_1),
      config_.query_open_orders_period_sec(),
      "query_open_orders",
      product_type_set);

  AddPeriodicTask(
      std::bind(&BitgetFuturesRestAsyncAsioSubscriber::QueryAllOrders, this, std::placeholders::_1),
      config_.query_cancel_orders_period_sec(),
      "query_all_orders",
      product_type_set);

  AddPeriodicTask(
      std::bind(
          &BitgetFuturesRestAsyncAsioSubscriber::QueryFillOrders,
          this,
          std::placeholders::_1),
      config_.query_fill_period_sec(),
      "query_fills",
      product_type_set);
}
}  // namespace coin2::exchange::bitget_futures::api_order
